package com.dynamic.model.util.redis;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;

public class RedisCacheUtil<T>
{

  @Autowired
  @Qualifier("redisTemplate")
  public RedisTemplate<String, T> redisTemplate;

  @Value("${redis.prefix}")
  private String prefix;

  private String getKey(String prefix, String key)
  {
    if (null!=prefix&&prefix.length()>0) {
      key = prefix + ":" + key;
    }
    return key;
  }

  public Set<String> keys(String pattern)
  {
    return this.redisTemplate.keys(pattern);
  }

  public void removeCache(String key)
  {
    removeCache(this.prefix, key);
  }
  public void removeCache(String prefix, String key) {
    this.redisTemplate.delete(getKey(prefix, key));
  }

  public boolean setCacheObject(String key, T value)
  {
    return setCacheObject(this.prefix, key, value);
  }
  public boolean setCacheObject(String prefix, String key, T value) {
    ValueOperations operation = this.redisTemplate.opsForValue();
    if (value != null) {
      operation.set(getKey(prefix, key), value);
      return true;
    }
    return false;
  }

  public boolean setCacheObject(String key, T value, long milliSerconds)
  {
    return setCacheObject(this.prefix, key, value, milliSerconds);
  }
  public boolean setCacheObject(String prefix, String key, T value, long milliSerconds) {
    ValueOperations operation = this.redisTemplate.opsForValue();
    if (value != null) {
      if (milliSerconds > 2147483647L)
        operation.set(getKey(prefix, key), value, milliSerconds / 1000L, TimeUnit.SECONDS);
      else {
        operation.set(getKey(prefix, key), value, milliSerconds, TimeUnit.MILLISECONDS);
      }
      return true;
    }
    return false;
  }

  public T getCacheObject(String key)
  {
    return getCacheObject(this.prefix, key);
  }
  public T getCacheObject(String prefix, String key) {
    ValueOperations operation = this.redisTemplate.opsForValue();
    return (T) operation.get(getKey(prefix, key));
  }

  public boolean setCacheList(String key, List<T> dataList, long milliSerconds)
  {
    return setCacheList(this.prefix, key, dataList, milliSerconds);
  }
  @Transactional
  public boolean setCacheList(String prefix, String key, List<T> dataList, long milliSerconds) {
    this.redisTemplate.expire(getKey(prefix, key), milliSerconds, TimeUnit.MILLISECONDS);
    ListOperations listOperation = this.redisTemplate.opsForList();
    if (dataList.size()>0) {
      listOperation.rightPushAll(getKey(prefix, key), dataList);
      return true;
    }

    return false;
  }

  public boolean setCacheList(String key, List<T> dataList)
  {
    return setCacheList(this.prefix, key, dataList);
  }
  public boolean setCacheList(String prefix, String key, List<T> dataList) {
    ListOperations listOperation = this.redisTemplate.opsForList();
    if (dataList.size()>0) {
      listOperation.rightPushAll(getKey(prefix, key), dataList);
      return true;
    }
    return false;
  }

  public List<T> getCacheList(String key)
  {
    return getCacheList(this.prefix, key);
  }
  public List<T> getCacheList(String prefix, String key) {
    List dataList = new ArrayList();
    ListOperations listOperation = this.redisTemplate.opsForList();
    long size = listOperation.size(getKey(prefix, key)).longValue();

    for (int i = 0; i < size; i++) {
      dataList.add(listOperation.leftPop(getKey(prefix, key)));
    }

    return dataList;
  }

  public boolean setCacheSet(String key, Set<T> dataSet, long milliSerconds)
  {
    return setCacheSet(this.prefix, key, dataSet, milliSerconds);
  }

  @Transactional
  public boolean setCacheSet(String prefix, String key, Set<T> dataSet, long milliSerconds) {
    this.redisTemplate.expire(getKey(prefix, key), milliSerconds, TimeUnit.MILLISECONDS);
    SetOperations setOperation = this.redisTemplate.opsForSet();

    if (dataSet.size()>0) {
      Iterator it = dataSet.iterator();
      while (it.hasNext()) {
        setOperation.add(getKey(prefix, key), new Object[] { it.next() });
      }
      return true;
    }
    return false;
  }

  public boolean setCacheSet(String key, Set<T> dataSet)
  {
    return setCacheSet(this.prefix, key, dataSet);
  }

  public boolean setCacheSet(String prefix, String key, Set<T> dataSet) {
    SetOperations setOperation = this.redisTemplate.opsForSet();

    if (dataSet.size()>0) {
      Iterator it = dataSet.iterator();
      while (it.hasNext()) {
        setOperation.add(getKey(prefix, key), new Object[] { it.next() });
      }
      return true;
    }
    return false;
  }

  public Set<T> getCacheSet(String key)
  {
    return getCacheSet(this.prefix, key);
  }
  public Set<T> getCacheSet(String prefix, String key) {
    Set dataSet = new HashSet();
    SetOperations setOperation = this.redisTemplate.opsForSet();

    Long size = setOperation.size(getKey(prefix, key));
    for (int i = 0; i < size.longValue(); i++) {
      dataSet.add(setOperation.pop(getKey(prefix, key)));
    }
    return dataSet;
  }

  public boolean setCacheMap(String key, Map<String, T> dataMap, long milliSerconds)
  {
    return setCacheMap(this.prefix, key, dataMap, milliSerconds);
  }
  @Transactional
  public boolean setCacheMap(String prefix, String key, Map<String, T> dataMap, long milliSerconds) {
    this.redisTemplate.expire(getKey(prefix, key), milliSerconds, TimeUnit.MILLISECONDS);
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (null != dataMap) {
      hashOperations.putAll(getKey(prefix, key), dataMap);
      return true;
    }
    return false;
  }

  public boolean setCacheMap(String key, Map<String, T> dataMap)
  {
    return setCacheMap(this.prefix, key, dataMap);
  }
  public boolean setCacheMap(String prefix, String key, Map<String, T> dataMap) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (null != dataMap) {
      hashOperations.putAll(getKey(prefix, key), dataMap);
      return true;
    }
    return false;
  }

  public Map<String, T> getCacheMap(String key)
  {
    return getCacheMap(this.prefix, key);
  }
  public Map<String, T> getCacheMap(String prefix, String key) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Map map = hashOperations.entries(getKey(prefix, key));
    return map;
  }

  public T getCacheMapValue(String key, String hashKey)
  {
    return getCacheMapValue(this.prefix, key, hashKey);
  }
  public T getCacheMapValue(String prefix, String key, String hashKey) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Object t = hashOperations.get(getKey(prefix, key), hashKey);
    return (T) t;
  }

  public boolean setCacheMapValue(String key, String hashKey, T value)
  {
    return setCacheMapValue(this.prefix, key, hashKey, value);
  }
  public boolean setCacheMapValue(String prefix, String key, String hashKey, T value) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (value != null) {
      hashOperations.put(getKey(prefix, key), hashKey, value);
      return true;
    }
    return false;
  }

  public void removeCacheMapKeys(String key, String[] hashKeys)
  {
    removeCacheMapKeys(this.prefix, key, hashKeys);
  }

  public void removeCacheMapKeys(String prefix, String key, String[] hashKeys) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Object[] keys = new Object[hashKeys.length];
    for (int i = 0; i < hashKeys.length; i++) {
      keys[i] = hashKeys[i];
    }
    hashOperations.delete(getKey(prefix, key), keys);
  }

  public boolean setCacheLongMap(String key, Map<Long, T> dataMap, long milliSerconds)
  {
    return setCacheLongMap(this.prefix, key, dataMap, milliSerconds);
  }
  @Transactional
  public boolean setCacheLongMap(String prefix, String key, Map<Long, T> dataMap, long milliSerconds) {
    this.redisTemplate.expire(getKey(prefix, key), milliSerconds, TimeUnit.MILLISECONDS);
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (null != dataMap) {
      hashOperations.putAll(getKey(prefix, key), dataMap);
      return true;
    }
    return false;
  }

  public boolean setCacheLongMap(String key, Map<Long, T> dataMap)
  {
    return setCacheLongMap(this.prefix, key, dataMap);
  }
  public boolean setCacheLongMap(String prefix, String key, Map<Long, T> dataMap) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (null != dataMap) {
      hashOperations.putAll(getKey(prefix, key), dataMap);
      return true;
    }
    return false;
  }

  public Map<Long, T> getCacheLongMap(String key)
  {
    return getCacheLongMap(this.prefix, key);
  }
  public Map<Long, T> getCacheLongMap(String prefix, String key) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Map map = hashOperations.entries(getKey(prefix, key));
    return map;
  }

  public T getCacheLongMapValue(String key, Long hashKey)
  {
    return getCacheLongMapValue(this.prefix, key, hashKey);
  }
  public T getCacheLongMapValue(String prefix, String key, Long hashKey) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Object t = hashOperations.get(getKey(prefix, key), hashKey);
    return (T) t;
  }

  public boolean setCacheLongMapValue(String key, Long hashKey, T value)
  {
    return setCacheLongMapValue(this.prefix, key, hashKey, value);
  }
  public boolean setCacheLongMapValue(String prefix, String key, Long hashKey, T value) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    if (value != null) {
      hashOperations.put(getKey(prefix, key), hashKey, value);
      return true;
    }
    return false;
  }

  public void removeCacheLongMapKeys(String key, Long[] hashKeys)
  {
    removeCacheLongMapKeys(this.prefix, key, hashKeys);
  }

  public void removeCacheLongMapKeys(String prefix, String key, Long[] hashKeys) {
    HashOperations hashOperations = this.redisTemplate.opsForHash();
    Object[] keys = new Object[hashKeys.length];
    for (int i = 0; i < hashKeys.length; i++) {
      keys[i] = hashKeys[i];
    }
    hashOperations.delete(getKey(prefix, key), keys);
  }

  public String getPrefix()
  {
    return this.prefix;
  }
  public void setPrefix(String prefix) {
    this.prefix = prefix;
  }
}